// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: donggu

static const char USAGE[] = R"(
    Order Debugger

    Usage:
      dbg --driver=<config_path>
      dbg  --mea=<mea> --product=<norm> --strat_machine=<strat_machine> --account=<account>
           [--start=<start>] [--duration=<duration>] [--end=<end>]

    Options:
      -h --help             Show this screen.
      --start=<start>       YYYY-MM-DD
      --end=<end>           YYYY-MM-DD
      --duration=<duration> PT1H
)";

#include <string>
#include <docopt/docopt.h>

#include "coin2/app/driver.h"
#include "coin2/base/config/app_config.h"
#include "coin2/base/config/args.h"
#include "coin2/exchange/base/order/order.h"
#include "coin2/strategy/strategy.h"
#include "coin/proto/coin_order_gateway.pb.h"

using coin2::exchange::base::order::OrderUpdate;
using coin2::exchange::base::order::OrderEvent;
using namespace coin2::app;
using namespace coin2::base::config;

int cnt = 0;

struct Strategy : public ::coin2::strategy::IStrategy {
  void onAccountOrder(const OrderUpdate& upd) override {
    auto& ev = upd.product_order_info().event();
    auto type = ev.type();
    cnt++;
    if (type == OrderEvent::ORDER_ERROR
        || type == OrderEvent::ORDER_REJECTED
        || type == OrderEvent::ORDER_EXPIRED
        || type == OrderEvent::CANCEL_ERROR
        || type == OrderEvent::CANCEL_REJECTED) {
      printf("===== [Error] %s\n", Iso8601FromTimestamp(upd.timestamp()).c_str());
      printf("%s\n\n", ev.DebugString().c_str());
    }
  }
};

DriverConfig parse_cli(int argc, char* argv[]) {
  std::map<std::string, docopt::value> args = docopt::docopt(
      USAGE,
      {argv + 1, argv + argc},
      true,                 // show help if requested
      "Coin2 Order Debugger");  // version string


  coin2::app::DriverConfig driver;
  if (args["--driver"]) {
    driver.MergeFrom(coin2::base::config::DriverConfigFromJson(args["--driver"].asString()));
  } else {
    // order
    {
      auto& exchanges = *driver.mutable_order()->mutable_exchanges();
      auto& exchange = exchanges[args["--mea"].asString()];

      exchange.set_mea(args["--mea"].asString());
      exchange.set_type(coin2::exchange::order::OrderSystemType::ORDER_SYSTEM_TYPE_ARCHIVE);
      exchange.mutable_products()->add_norms(args["--product"].asString());
      exchange.mutable_archive()->set_machine(args["--strat_machine"].asString());
      exchange.mutable_archive()->set_owner(args["--account"].asString());
    }
  }

  {
    auto& order_interval =
        *driver.mutable_order()->mutable_common()->mutable_archive()->mutable_interval();
    if (args["--start"]) {
      order_interval.set_start(args["--start"].asString());
    }
    if (args["--duration"]) {
      order_interval.set_duration(args["--duration"].asString());
    }
    if (args["--end"]) {
      order_interval.set_duration(args["--end"].asString());
    }
  }

  return driver;
}

int main(int argc, char* argv[]) {
  auto app = parse_cli(argc, argv);

  /* ----------------------------------- run ---------------------------------- */
  printf("reading ..\n");

  Strategy strategy;
  ::coin2::app::Driver driver(app, &strategy);
  driver.Run();

  printf("done .\n\n");
  printf("total order logs: %d\n", cnt);

  return 0;
}
